Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ


Displaying Rendered β€’ View raw β€’ Download

feature/connections/README.md bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 7.01 KB

T383838:feature:connections

Overview

The T383838:feature:connections module provides the device discovery and connection management screen. It enables users to scan for and connect to Meshtastic radios over BLE, USB serial, and TCP/NSD (network service discovery). The T383838ScannerViewModel is platform-neutral; Android and JVM subclasses supply platform-specific bonding and permission workflows.

Targets: Android Β· JVM (Desktop) Β· iOS (via T383838meshtastic.kmp.feature convention plugin)

Key Responsibilities

β€’ Scan for BLE devices and merge results with previously bonded devices (bonded first, then discovery order)
β€’ Enumerate USB serial devices (CH340, FTDI, CP21xx, etc.) with permission gating on Android
β€’ Discover TCP/NSD services and manage recent manual TCP addresses
β€’ Surface a single-choice transport selector (BLE / Network / USB) whose active pane persists to DataStore
β€’ Manage the full connection flow: bond β†’ connect β†’ disconnect
β€’ Show connection status and progress while a device is being configured

Source Structure

T282828
src/
β”œβ”€β”€ commonMain/kotlin/org/meshtastic/feature/connections/
β”‚ β”œβ”€β”€ ScannerViewModel.kt ← platform-neutral ViewModel
β”‚ β”œβ”€β”€ Constants.kt
β”‚ β”œβ”€β”€ model/
β”‚ β”‚ β”œβ”€β”€ DeviceListEntry.kt ← sealed: Ble | Usb | Tcp | Mock | Replay
β”‚ β”‚ └── DiscoveredDevices.kt ← GetDiscoveredDevicesUseCase interface + result
β”‚ β”œβ”€β”€ domain/usecase/
β”‚ β”‚ β”œβ”€β”€ CommonGetDiscoveredDevicesUseCase.kt
β”‚ β”‚ β”œβ”€β”€ TcpDiscoveryHelpers.kt
β”‚ β”‚ └── UsbScanner.kt ← common USB scanner interface
β”‚ β”œβ”€β”€ navigation/
β”‚ β”‚ └── ConnectionsNavigation.kt
β”‚ β”œβ”€β”€ ui/
β”‚ β”‚ β”œβ”€β”€ ConnectionsScreen.kt
β”‚ β”‚ └── components/
β”‚ β”‚ β”œβ”€β”€ ConnectingDeviceInfo.kt
β”‚ β”‚ β”œβ”€β”€ ConnectionActionButton.kt
β”‚ β”‚ β”œβ”€β”€ CurrentlyConnectedInfo.kt
β”‚ β”‚ β”œβ”€β”€ DeviceList.kt / DeviceListItem.kt / DeviceSectionHeader.kt
β”‚ β”‚ β”œβ”€β”€ DisconnectButton.kt
β”‚ β”‚ β”œβ”€β”€ EmptyStateContent.kt
β”‚ β”‚ └── TransportSelector.kt
β”‚ └── di/
β”‚ └── FeatureConnectionsModule.kt
β”œβ”€β”€ androidMain/kotlin/
β”‚ β”œβ”€β”€ AndroidScannerViewModel.kt ← overrides bond/permission requests
β”‚ └── domain/usecase/AndroidGetDiscoveredDevicesUseCase.kt
└── jvmMain/kotlin/
β”œβ”€β”€ JvmScannerViewModel.kt
└── domain/usecase/JvmGetDiscoveredDevicesUseCase.kt

Key Types

T383838DeviceListEntry (sealed class)

T282828
Tff7b72sealed Tff7b72class T56d364DeviceListEntry Tb4b4b4{
Tff7b72data Tff7b72class T56d364BleTb4b4b4(Te6edf3deviceTb4b4b4: Te6edf3BleDeviceTb4b4b4, Te6edf3bondedTb4b4b4: Tffa657BooleanTb4b4b4, Te6edf3nodeTb4b4b4: Te6edf3Node?Tb4b4b4) Tb4b4b4: Te6edf3DeviceListEntryTb4b4b4(Tb4b4b4)
Tff7b72data Tff7b72class T56d364UsbTb4b4b4(Te6edf3usbDataTb4b4b4: Te6edf3UsbDeviceDataTb4b4b4, Te6edf3nameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3fullAddressTb4b4b4: Tffa657StringTb4b4b4, Tb4b4b4.Tb4b4b4.Tb4b4b4.Tb4b4b4) Tb4b4b4: Te6edf3DeviceListEntryTb4b4b4(Tb4b4b4)
Tff7b72data Tff7b72class T56d364TcpTb4b4b4(Te6edf3nameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3fullAddressTb4b4b4: Tffa657StringTb4b4b4, Te6edf3nodeTb4b4b4: Te6edf3Node?Tb4b4b4) Tb4b4b4: Te6edf3DeviceListEntryTb4b4b4(Tb4b4b4)
Tff7b72data Tff7b72class T56d364MockTb4b4b4(Te6edf3nameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3nodeTb4b4b4: Te6edf3Node?Tb4b4b4) Tb4b4b4: Te6edf3DeviceListEntryTb4b4b4(Tb4b4b4)
Tff7b72data Tff7b72class T56d364ReplayTb4b4b4(Te6edf3nameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3nodeTb4b4b4: Te6edf3Node?Tb4b4b4) Tb4b4b4: Te6edf3DeviceListEntryTb4b4b4(Tb4b4b4)

Tff7b72abstract Tff7b72val Te6edf3addressTb4b4b4: Tffa657String T8b949e// strips transport prefix
Tff7b72abstract Tff7b72fun Td2a8ffcopyTb4b4b4(Te6edf3nodeTb4b4b4: Te6edf3Node?Tb4b4b4)Tb4b4b4: Te6edf3DeviceListEntry
Tb4b4b4}


Address format conventions: BLE β†’ T383838x<MAC>, USB β†’ T383838s<path>, TCP β†’ T383838t<host:port>, Mock β†’ T383838m, Replay β†’ T383838r.

T383838ScannerViewModel

Platform-neutral ViewModel. Exposes:

T282828
T8b949e// Device lists
Tff7b72val Te6edf3bleDevicesForUiTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3ListTff7b72<Te6edf3DeviceListEntryTff7b72>Tff7b72>
Tff7b72val Te6edf3usbDevicesForUiTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3ListTff7b72<Te6edf3DeviceListEntryTff7b72>Tff7b72>
Tff7b72val Te6edf3discoveredTcpDevicesForUiTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3ListTff7b72<Te6edf3DeviceListEntryTff7b72>Tff7b72>
Tff7b72val Te6edf3recentTcpDevicesForUiTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3ListTff7b72<Te6edf3DeviceListEntryTff7b72>Tff7b72>

T8b949e// Scan state
Tff7b72val Te6edf3activeTransportTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3DeviceTypeTff7b72>
Tff7b72val Te6edf3isBleScanningTb4b4b4: Te6edf3StateFlowTff7b72<Tffa657BooleanTff7b72>
Tff7b72val Te6edf3isNetworkScanningTb4b4b4: Te6edf3StateFlowTff7b72<Tffa657BooleanTff7b72>

T8b949e// Connection
Tff7b72val Te6edf3connectionProgressTextTb4b4b4: Te6edf3StateFlowTff7b72<Tffa657String?Tff7b72>
Tff7b72val Te6edf3selectedAddressFlowTb4b4b4: Te6edf3StateFlowTff7b72<Tffa657String?Tff7b72>

T8b949e// Actions
Tff7b72fun Td2a8ffselectTransportTb4b4b4(Te6edf3typeTb4b4b4: Te6edf3DeviceTypeTb4b4b4)
Tff7b72fun Td2a8ffstartBleScanTb4b4b4(Tb4b4b4) Tff7b72/ Te6edf3stopBleScanTb4b4b4(Tb4b4b4) Tff7b72/ Te6edf3toggleBleScanTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffstartBleAutoScanTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffstartNetworkScanTb4b4b4(Tb4b4b4) Tff7b72/ Te6edf3stopNetworkScanTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffstartNetworkAutoScanTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffpersistNetworkAutoScanIntentTb4b4b4(Te6edf3enabledTb4b4b4: Tffa657BooleanTb4b4b4)
Tff7b72fun Td2a8ffconnectToManualAddressTb4b4b4(Te6edf3fullAddressTb4b4b4: Tffa657StringTb4b4b4)
Tff7b72fun Td2a8ffonSelectedTb4b4b4(Te6edf3entryTb4b4b4: Te6edf3DeviceListEntryTb4b4b4)Tb4b4b4: Tffa657Boolean T8b949e// false if bond/permission still pending
Tff7b72fun Td2a8ffdisconnectTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffaddRecentAddressTb4b4b4(Te6edf3addressTb4b4b4: Tffa657StringTb4b4b4, Te6edf3nameTb4b4b4: Tffa657StringTb4b4b4)
Tff7b72fun Td2a8ffremoveRecentAddressTb4b4b4(Te6edf3addressTb4b4b4: Tffa657StringTb4b4b4)


Android and JVM subclasses override T383838requestBonding(entry) and T383838requestPermission(entry) to perform OS-level Bluetooth pairing and USB permission dialogs respectively.

Navigation

T282828
T8b949e// Registration (in androidApp / desktopApp nav graph)
Tff7b72fun Td2a8ffEntryProviderScopeTff7b72<Te6edf3NavKeyTff7b72>Tb4b4b4.Te6edf3connectionsGraphTb4b4b4(Te6edf3backStackTb4b4b4: Te6edf3NavBackStackTff7b72<Te6edf3NavKeyTff7b72>Tb4b4b4) Tb4b4b4{
T8b949e// Registers ConnectionsRoute.Connections entry
T8b949e// Injects ScannerViewModel via Koin
Tb4b4b4}


Route: T383838ConnectionsRoute.Connections

Dependency Graph

Key Dependencies

T282828
feature:connections
β”œβ”€β”€ core:ble, core:network (transports)
β”œβ”€β”€ core:common, core:data, core:database, core:datastore, core:di
β”œβ”€β”€ core:domain, core:model, core:navigation
β”œβ”€β”€ core:prefs, core:resources, core:service, core:ui
β”œβ”€β”€ org.meshtastic:protobufs (Maven artifact)
└── usb-serial-android (Android only)

<!--region graph-->
T282828
Te6edf3graph Te6edf3TB
:Te6edf3featureTb4b4b4:Te6edf3connectionsTff7b72[Te6edf3connectionsTff7b72]Tff7b72:::Te6edf3kmpTff7b72-Te6edf3feature
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3common
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Tff7b72data
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Tff7b72database
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3datastore
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3di
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Tff7b72domain
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3model
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3navigation
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3prefs
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3resources
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3service
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3ui
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3ble
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3network
:Te6edf3featureTb4b4b4:Te6edf3connections Tff7b72-Tb4b4b4.Tff7b72-Tff7b72> :Te6edf3coreTb4b4b4:Te6edf3testing

Te6edf3classDef Te6edf3androidTff7b72-Te6edf3application Te6edf3fillTb4b4b4:Te6edf3#CAFFBFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3applicationTff7b72-Te6edf3compose Te6edf3fillTb4b4b4:Te6edf3#CAFFBFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3composeTff7b72-Te6edf3desktopTff7b72-Te6edf3application Te6edf3fillTb4b4b4:Te6edf3#CAFFBFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3feature Te6edf3fillTb4b4b4:Te6edf3#FFD6A5Tb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3library Te6edf3fillTb4b4b4:Te6edf3#9BF6FFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3libraryTff7b72-Te6edf3compose Te6edf3fillTb4b4b4:Te6edf3#9BF6FFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3androidTff7b72-Te6edf3test Te6edf3fillTb4b4b4:Te6edf3#A0C4FFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3jvmTff7b72-Te6edf3library Te6edf3fillTb4b4b4:Te6edf3#BDB2FFTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3kmpTff7b72-Te6edf3feature Te6edf3fillTb4b4b4:Te6edf3#FFD6A5Tb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3kmpTff7b72-Te6edf3libraryTff7b72-Te6edf3compose Te6edf3fillTb4b4b4:Te6edf3#FFC1CCTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Te6edf3kmpTff7b72-Te6edf3library Te6edf3fillTb4b4b4:Te6edf3#FFC1CCTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;
Te6edf3classDef Tff7b72unknown Te6edf3fillTb4b4b4:Te6edf3#FFADADTb4b4b4,Te6edf3strokeTb4b4b4:Te6edf3#000Tb4b4b4,Te6edf3strokeTff7b72-Te6edf3widthTb4b4b4:T79c0ff2Te6edf3pxTb4b4b4,Te6edf3colorTb4b4b4:Te6edf3#000Tb4b4b4;


<!--endregion-->

Served by rngit 1.5.0 - Generated in 0.08s